package common

import (
	"flag"
	"go-project/config"
	"log/slog"
	"os"

	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/go-redis/redis/v8"
	"gopkg.in/yaml.v2"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var AutoMigrate = make([]any, 0)

var (
	CONFIG   *config.Config
	DB       *gorm.DB
	REDIS    *redis.Client
	ENFORCER *casbin.Enforcer
)

func Init() {
	var conf string
	flag.StringVar(&conf, "conf", "dev.yml", "")
	flag.Parse()
	ymlFile, err := os.ReadFile(conf)
	if err != nil {
		panic(err)
	}
	err = yaml.Unmarshal(ymlFile, &CONFIG)
	if err != nil {
		panic(err)
	}

	initLog()
	initRedis()
	initGorm()
	initCasbin()
}

func initRedis() {
	REDIS = redis.NewClient(&redis.Options{
		Addr:     CONFIG.Redis.Addr,
		Password: CONFIG.Redis.Password,
		DB:       CONFIG.Redis.DB,
	})
}

func initGorm() {
	db, err := gorm.Open(mysql.Open(CONFIG.Mysql), &gorm.Config{Logger: logger.Default.LogMode(logger.Info)})
	if err != nil {
		panic(err)
	}
	DB = db
}

func initCasbin() {
	var m = model.NewModel()

	m.AddDef("r", "r", "sub, obj, act")
	m.AddDef("p", "p", "sub, obj, act")
	m.AddDef("g", "g", "_, _")
	m.AddDef("e", "e", "some(where (p.eft == allow))")
	m.AddDef("m", "m", "g(r.sub, p.sub) && globMatch(r.obj, p.obj) && r.act == p.act")
	a, err := gormadapter.NewAdapterByDB(DB)
	if err != nil {
		panic(err)
	}
	enforcer, err := casbin.NewEnforcer(m, a)
	if err != nil {
		panic(err)
	}
	ENFORCER = enforcer
}

func initLog() {
	//logHandler := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
	//	AddSource:   false,
	//	Level:       slog.LevelDebug,
	//	ReplaceAttr: nil,
	//}))
	//slog.SetDefault(logHandler)
	var logLevel slog.Level
	switch CONFIG.Log.Level {
	case "debug":
		logLevel = slog.LevelDebug
	case "info":
		logLevel = slog.LevelInfo
	case "warn":
		logLevel = slog.LevelWarn
	case "error":
		logLevel = slog.LevelError
	default:
		logLevel = slog.LevelInfo
	}
	//log.SetPrefix("[SLOG] ")
	slog.SetLogLoggerLevel(logLevel)
}
